package cn.geminis.crypto.tsp;

import cn.geminis.core.util.DateUtils;
import cn.geminis.crypto.core.util.ProviderUtils;
import cn.geminis.crypto.core.util.SerialNumberUtils;
import cn.geminis.crypto.core.x509.X509Certificate;
import cn.geminis.crypto.csp.AbstractSigner;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.SignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampTokenGenerator;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Allen
 */
public class TimeStampResponseGenerator {

    private org.bouncycastle.tsp.TimeStampResponseGenerator generator;

    public TimeStampResponseGenerator(AbstractSigner signer, X509Certificate issuer, String tsaPolicy) {

        SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(
                ProviderUtils.getDigestCalculatorProvider());
        X509CertificateHolder certificateHolder = new X509CertificateHolder(issuer.getBcCertificate());
        SignerInfoGenerator signerInfoGenerator;
        try {
            ContentSigner contentSigner = signer.createContentSigner();
            signerInfoGenerator = signerInfoGeneratorBuilder.build(contentSigner, certificateHolder);
        } catch (OperatorCreationException e) {
            throw new RuntimeException("创建签名者信息生成器错误", e);
        }

        TimeStampTokenGenerator tokenGenerator;
        try {
            tokenGenerator = new TimeStampTokenGenerator(
                    signerInfoGenerator,
                    ProviderUtils.getDigestCalculatorProvider()
                            .get(new AlgorithmIdentifier(new ASN1ObjectIdentifier(signer.getDigestAlgOid()))),
                    new ASN1ObjectIdentifier(tsaPolicy));
        } catch (Exception e) {
            throw new RuntimeException("创建时间戳生成器错误", e);
        }

        Set<String> acceptedAlgorithms = new HashSet<>();
        acceptedAlgorithms.add(signer.getDigestAlgOid());
        this.generator = new org.bouncycastle.tsp.TimeStampResponseGenerator(tokenGenerator, acceptedAlgorithms);
    }

    public TimeStampResponse response(TimeStampRequest request, BigInteger serialNumber, LocalDateTime time) {
        org.bouncycastle.tsp.TimeStampResponse response;
        try {
            response = this.generator.generate(request.getBcRequest(), serialNumber, DateUtils.toDate(time));
        } catch (TSPException e) {
            throw new RuntimeException("创建时间戳响应错误", e);
        }
        return new TimeStampResponse(response);
    }

    public TimeStampResponse response(TimeStampRequest request) {
        return response(request, SerialNumberUtils.create(), LocalDateTime.now());
    }

}
